test: null/dictionary bind columns, empty bound batch schema, int option coherence - #4
Closed
fornwall wants to merge 3 commits into
Closed
test: null/dictionary bind columns, empty bound batch schema, int option coherence#4fornwall wants to merge 3 commits into
fornwall wants to merge 3 commits into
Conversation
Two generic bind-parameter acceptance tests, gated on statement_bind: - test_parameter_null_typed binds a batch whose parameter column has Arrow type null. AdbcStatementGetParameterSchema (adbc.h) reports NA (NullType) fields when a parameter type cannot be determined, so a batch built from the driver's own reported parameter schema (or pyarrow's inferred type for an all-None parameter set, as produced by DBAPI executemany) is null-typed; drivers must bind NULL per row. - test_parameter_dictionary_encoded binds a dictionary-encoded string column (what pandas categoricals produce). Dictionary encoding is an encoding of the same logical values, not a different logical type (Arrow columnar format, Dictionary-encoded Layout), so a driver that binds strings should accept it, decoding if needed. Both reuse the existing sample_table fixture (and its query_override hook), inserting via bound parameters and reading the rows back. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LGf8PVEe2tYkw8Q6Pd95tq Signed-off-by: Fredrik Fornwall <fredrik@fornwall.net>
Implements the 'empty stream/empty batch' TODO in TestQuery.test_query as a self-contained statement-level test, gated on statement_bind: test_parameter_execute_empty_bind executes a parameterized SELECT with a zero-row bound batch (the DBAPI executemany empty-parameter-set shape) and asserts the returned stream has zero rows but still carries the query's real result schema, matching a non-empty execution of the same query. The result schema is a property of the query, not of the number of bound rows; the ADBC spec does not spell the zero-row case out explicitly, so this asserts the self-consistency invariant. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LGf8PVEe2tYkw8Q6Pd95tq Signed-off-by: Fredrik Fornwall <fredrik@fornwall.net>
…etOptionInt adbc.h (AdbcConnectionGetOptionInt): 'For standard options, drivers must always support getting the option value (if they support getting option values at all) via the type specified in the option. (For example, an option set via SetOptionDouble must be retrievable via GetOptionDouble.)' test_option_autocommit_int_coherence sets adbc.connection.autocommit through SetOptionInt (a plain Python int via set_options) and, when the driver accepts that set, requires GetOptionInt to succeed and agree (and the string getter to agree as well). Drivers that reject the integer-typed set are skipped, not failed. Gated on connection_transactions since the test toggles autocommit off; restores autocommit afterwards like test_transaction_toggle. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LGf8PVEe2tYkw8Q6Pd95tq Signed-off-by: Fredrik Fornwall <fredrik@fornwall.net>
This was referenced Jul 13, 2026
Owner
Author
|
Superseded — split into one PR per test as requested, each carrying the adbc-spanner emulator evidence plus new results against the released adbc-driver-sqlite 1.11.0 wheel:
The combined branch test/review-gap-tests is left in place for reference. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds four generic, driver-agnostic tests for gaps found while reviewing an ADBC driver (the adbc-spanner Rust driver) against this suite: each one encodes a contract the suite did not previously exercise and that a real driver got wrong. They are candidates for upstreaming to adbc-drivers/validation later.
Tests
1.
TestStatement.test_parameter_null_typed(gated onstatement_bind)Binds a batch whose parameter column has Arrow type
nulland asserts NULL is bound per row (insert + read-back through the existingsample_tablefixture / itsquery_overridehook).Reference:
AdbcStatementGetParameterSchemadoc comment inadbc.h: "If the type cannot be determined, the type of the corresponding field will be NA (NullType)." A client that builds its bind batch from the driver's own reported parameter schema therefore produces null-typed columns; pyarrow also infersnullfor an all-Noneparameter set (the DBAPIexecutemanyshape). A driver advertising bind support that rejects the type its ownGetParameterSchemahands out contradicts itself.Expected on current adbc-spanner: FAIL (verified by emulator run):
INVALID_ARGUMENT: cannot bind parameter "p2": unsupported Arrow type Null(REVIEW.md finding CONV-1 —bind.rshas noNullarm).2.
TestStatement.test_parameter_dictionary_encoded(gated onstatement_bind)Binds a dictionary-encoded string column (
pa.array([...]).dictionary_encode()— what pandas categoricals produce over the C data interface) and asserts the decoded values (including a null) round-trip.Reference: the Arrow columnar format, "Dictionary-encoded Layout": dictionary encoding is a representation of the same logical values, not a different logical type. No ADBC spec text explicitly requires drivers to accept every Arrow encoding, so this test asserts an ecosystem-consistency expectation stated here explicitly: a driver that binds plain string columns should accept (and may decode) the dictionary-encoded equivalent, since that is what common producers (pandas) emit.
Expected on current adbc-spanner: FAIL (verified by emulator run): the Arrow-to-Spanner bind path rejects
Dictionarywholesale (REVIEW.md finding CONV-2).3.
TestStatement.test_parameter_execute_empty_bind(gated onstatement_bind)Implements the long-standing
# TODO: also test with empty stream/empty batchinTestQuery.test_query(comment adjusted there): executes a parameterizedSELECTwith a zero-row bound batch and asserts the returned stream has zero rows but still carries the query's real result schema, identical to a non-empty execution of the same query.Reference: no ADBC spec text spells out the zero-bound-rows case (
AdbcStatementBindsays only that bind is for "bulk inserts or prepared statements"). This test asserts a self-consistency invariant, stated here explicitly rather than cited: the result schema is a property of the query, not of the number of bound rows, so an emptyexecutemanyparameter set must not change the schema a client sees.Expected on current adbc-spanner: FAIL (verified by emulator run): the empty-bind execution returns an empty (0-column) schema instead of the query's schema (REVIEW.md finding COR-9).
4.
TestConnection.test_option_autocommit_int_coherence(gated onconnection_transactions)Sets
adbc.connection.autocommitthroughSetOptionInt(a plain Pythonintviaset_options); if the driver accepts that set, requiresGetOptionInton the same key to succeed and agree, and the string getter to agree too. Drivers that reject the integer-typed set are skipped, not failed. Restores autocommit afterwards (same pattern astest_transaction_toggle, which covers the bool-as-string round-trip; this test is specifically the int-typed accessor coherence).Reference:
AdbcConnectionGetOptionIntdoc comment inadbc.h: "For standard options, drivers must always support getting the option value (if they support getting option values at all) via the type specified in the option. (For example, an option set via SetOptionDouble must be retrievable via GetOptionDouble.)" The skip-on-rejected-set keeps the test within that text: it only asserts the getter once the driver has itself accepted the int-typed set.Expected on current adbc-spanner: FAIL (verified by emulator run): the int set succeeds but
get_option_interrors (value "true" is not an integer) (REVIEW.md finding COR-4).Verification
uv run pytest tests/(210 passed, 1 skipped),uv run ty check(clean),pre-commit run --all-files(all hooks pass).test_prepare,test_transaction_toggle,test_nonascii_queries) still passes on the same driver with this branch installed.🤖 Generated with Claude Code
https://claude.ai/code/session_01LGf8PVEe2tYkw8Q6Pd95tq